package org.eda2;

import java.util.ArrayList;

/**
 * Clase CalculoInspeccionDinamica. Clase que mediante la tecnica de
 * Programacion Dinamica, devuelve los usuarios que maximizan el beneficio de su
 * inspeccion.
 */
public class CalculoInspeccionDinamica {

	/**
	 * Metodo CalculoTiempoInspeccion. Metodo que calcula los tiempo de
	 * inspeccion que sera necesario aplicar pora cada usuario de dicha lista
	 * Este metodo rellena dicho atributo de todos los usuarios de la lista.
	 * 
	 * @param userList
	 *            . Variable de tipo ArrayList. Hace referencia a los usuarios
	 *            sobre los que vamos a calcular el nuevo atributo incluido en
	 *            esta practica, llamado tiempoInspec.
	 * @return userList. Variable de tipo ArrayList. Hace referencia a la misma
	 *         lista de usuarios inicial pasada por parametro, pero con los
	 *         atributos nuevos calculados.
	 */
	public static ArrayList<User> calculoTiempoInspeccion(
			ArrayList<User> userList) {
		double aux = 0;
		for (User user : userList) {
			// Calculamos el valor del tmi para cada usuario....
			aux = (30.0 * (Math.log((user.getIce() / 1500.0) + 1.0) / Math
					.log(2))) + 9.0;
			if (aux / 15 < 1) {
				user.setTiempoInspec(2);
				continue;
			}
			if (aux / 15 > 9) {
				user.setTiempoInspec(10);
				continue;
			}
			// Reajustamos al alza los valores...
			if (aux % 15 == 0.0) {
				user.setTiempoInspec(((int) (aux / 15)) + 1);
				continue;
			}
			if (aux % 15 > 0) {
				user.setTiempoInspec(((int) (aux / 15)) + 2);
				continue;
			}
		}
		return userList;
	}

	/**
	 * Metodo Mochila. Metodo que rellena la matriz segun una lista de usuarios,
	 * donde las columnas representan su peso, y las filas, representan los
	 * ususarios.
	 * 
	 * @param usuarios
	 *            . Varible de tipo ArrayList. Hace referencia a la lista de
	 *            usuarios sobre la que vamos a calcular cuales de ellos
	 *            maximizan el beneficio de su inspeccion en base al tiempo.
	 * @param capacidad
	 *            . Variable de tipo int. Hace referencia a la capacidad de
	 *            nuestra mochila.
	 * @return matriz_mochila. Variable de tipo matriz. Hace referencia a la
	 *         matriz que formamos con los usuarios dados y su peso, para
	 *         calcular el beneficio.
	 */
	public static int[][] mochila(ArrayList<User> usuarios, int capacidad) {

		// Creamos la matriz de devoluciones
		int[][] matriz_mochila = new int[usuarios.size() + 1][capacidad + 1];

		// Rellenamos la primera fila de ceros
		for (int i = 0; i <= capacidad; i++)
			matriz_mochila[0][i] = 0;

		// Rellenamos la primera columna de ceros
		for (int i = 0; i <= usuarios.size(); i++)
			matriz_mochila[i][0] = 0;

		// Rellenamos el resto de la matriz
		for (int j = 1; j <= usuarios.size(); j++)
			for (int c = 1; c <= capacidad; c++) {
				if (c < usuarios.get(j - 1).getTiempoInspec()) {
					matriz_mochila[j][c] = matriz_mochila[j - 1][c];
				} else {
					if (matriz_mochila[j - 1][c] > matriz_mochila[j - 1][c
							- usuarios.get(j - 1).getTiempoInspec()]
							+ usuarios.get(j - 1).getDiferencia()) {
						matriz_mochila[j][c] = matriz_mochila[j - 1][c];
					} else {
						matriz_mochila[j][c] = matriz_mochila[j - 1][c
								- usuarios.get(j - 1).getTiempoInspec()]
								+ usuarios.get(j - 1).getDiferencia();

//						System.out.println((j - 1) + "     "
//								+ (c - usuarios.get(j - 1).getTiempoInspec())
//								+ "         "
//								+ usuarios.get(j - 1).getDiferencia());
					}
				}
			}
		return matriz_mochila;
	}

	/**
	 * Metodo getUsuariosAInspeccionar. Metodo que devuelve una lista de
	 * usuarios que maximizan el beneficio de su inspeccion en base a la matriz
	 * beneficio/tiempo pasada por parametro.
	 * 
	 * @param userTiempoInspecc
	 *            . Variable de tipo ArrayList. Hace referencia a los usuarios a
	 *            inspeccionar, de los cuales queremos maximinar el beneficio.
	 * @param tablaDinamica
	 *            . Variable de tipo matriz. Hace referencia a la tabla de
	 *            beneficio de los usuarios a inspeccionar.
	 * @return solucionPDinamica. Variable de tipo ArrayList. Hace referencia a
	 *         los usuarios resultantes del estudio, los cuales maximizan el
	 *         beneficio de inspeccion.
	 */
	public static ArrayList<User> getUsuariosAInspeccionar(
			ArrayList<User> userTiempoInspecc, int[][] tablaDinamica) {

		ArrayList<User> solucionPDinamica = new ArrayList<User>();

		int i = tablaDinamica.length - 1;
		// Por cada nueva pasada por el bucle disminuimos una fila...
		for (int j = tablaDinamica[0].length - 1; j > 0 && i > 0; i--) {
			if (tablaDinamica[i][j] != tablaDinamica[i - 1][j]) {
				// Si son distintos, el ultimo elemento se incluye en la
				// solucion...
				solucionPDinamica.add(userTiempoInspecc.get(i - 1));
				// Calculamos el nuevo peso, tras la insercion de un nuevo
				// usuario (desplazamos columna).
				j -= userTiempoInspecc.get(i - 1).getTiempoInspec();
			}
		}
		return solucionPDinamica;
	}
}
